﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using System.Linq;

namespace Gmantis.Controls.DataGrid
{
    internal class DataGridColumnsHeaderManager
    {
        // Fields
        private Canvas _canvas;
        private Canvas _draggingLayer;
        private ContentControl _dragSourceColumn;
        private Canvas _fixedColumnsLayer;
        private Point _lastMousePosition;
        private Popup _popup;
        private Canvas _scrollableColumnsLayer;
        private double _scrollOffset;
        private DispatcherTimer _scrollTimer;
        private bool _selectedCellIsEditing;
        private DataGridColumn _selectedColumn;
        private DataGridRow _selectedRow;
        private Point _sourceInnerOffset;
        private int _targetGroupingIndex = -1;
        private bool dragging;
        private bool SourceIsInGroupingPanel;
        private ViewColumn SourceViewColumn;
        private DataGridColumnHeaderPresenter TargetColumnHeader;

        // Methods
        public DataGridColumnsHeaderManager(DataGridView view, Popup popup)
        {
            DispatcherTimer timer = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(0.033333333333333333)
            };
            this._scrollTimer = timer;
            this.View = view;
            this._popup = popup;
            this._scrollTimer.Tick += new EventHandler(this.ScrollTick);
            if (this.GroupingPresenter != null)
            {
                DragHelper helper = new DragHelper(this.GroupingPresenter, DragHelperMode.TranslateXY, 1.0, false, false, false, false);
                helper.DragStarted += new EventHandler<DragStartedEventArgs>(this.OnDragStarted);
                helper.DragDelta += new EventHandler<DragDeltaEventArgs>(this.OnDragDelta);
                helper.DragCompleted += new EventHandler<DragCompletedEventArgs>(this.OnDragCompleted);
            }
            if (this.ColumnsHeaderPanel != null)
            {
                DragHelper helper2 = new DragHelper(this.ColumnsHeaderPanel, DragHelperMode.TranslateXY, 1.0, false, false, false, false);
                helper2.DragStarted += new EventHandler<DragStartedEventArgs>(this.OnDragStarted);
                helper2.DragDelta += new EventHandler<DragDeltaEventArgs>(this.OnDragDelta);
                helper2.DragCompleted += new EventHandler<DragCompletedEventArgs>(this.OnDragCompleted);
            }
        }

        private int CalculateTargetColumnIndex()
        {
            Point point = this._canvas.TransformToVisual(this.TargetColumnHeader).Transform(this._lastMousePosition);
            return (this.TargetViewColumn.Column.DisplayIndex + (((point.X < (this.TargetColumnHeader.ActualWidth / 2.0)) || (this.TargetViewColumn == this.SourceViewColumn)) ? 0 : 1));
        }

        private void ClearLayers()
        {
            this._draggingLayer.Children.Clear();
            this._fixedColumnsLayer.Children.Clear();
            this._scrollableColumnsLayer.Children.Clear();
        }

        private void ClipColumnLayers()
        {
            if (this.DataGrid.GetTopMostParent() is FrameworkElement)
            {
                Point point = this.ColumnsHeaderPanel.TransformToVisual(this._canvas).Transform(new Point());
                RectangleGeometry geometry = new RectangleGeometry
                {
                    Rect = new Rect(new Point(point.X, point.Y), new Point(point.X + this.DataGrid.View.GetFrozenWidth(true), point.Y + this.View.RowsPanel.RenderSize.Height))
                };
                this._fixedColumnsLayer.Clip = geometry;
                RectangleGeometry geometry2 = new RectangleGeometry
                {
                    Rect = new Rect(new Point(point.X + this.DataGrid.View.GetFrozenWidth(true), point.Y - 1.0), new Point(point.X + this.View.RowsPanel.RenderSize.Width, point.Y + this.View.RowsPanel.RenderSize.Height))
                };
                this._scrollableColumnsLayer.Clip = geometry2;
            }
        }

        private void DrawMarker(Canvas layer, Point pos, UIElement marker)
        {
            layer.Children.Add(marker);
            Canvas.SetLeft(marker, pos.X);
            Canvas.SetTop(marker, pos.Y);
        }

        private void DrawSourceMarkers()
        {
            DataGridColumnHeaderPresenter columnHeader = this.GetColumnHeader(this.SourceViewColumn, this.SourceIsInGroupingPanel);
            if (columnHeader != null)
            {
                ContentControl control = new ContentControl
                {
                    Background = this.DataGrid.PressedBrush,
                    BorderThickness = this.DataGrid.BorderThickness,
                    Style = this.DataGrid.DragSourceColumnStyle,
                    Width = columnHeader.ActualWidth + 1.0,
                    Height = columnHeader.ActualHeight + 1.0,
                    Margin = new Thickness(-1.0, -1.0, 0.0, 0.0)
                };
                this._dragSourceColumn = control;
                this.DrawMarker(this.SourceIsInGroupingPanel ? this._draggingLayer : ((this.SourceViewColumn.Column.DisplayIndex < this.DataGrid.FrozenColumnCount) ? this._fixedColumnsLayer : this._scrollableColumnsLayer), columnHeader.TransformToVisual(this._canvas).Transform(new Point()), this._dragSourceColumn);
            }
        }

        private void DrawTargetMarkers()
        {
            Point point = this.ColumnsHeaderPanel.TransformToVisual(this._canvas).Transform(new Point());
            ContentControl marker = new ContentControl
            {
                Background = this.DataGrid.PressedBrush,
                BorderThickness = this.DataGrid.BorderThickness,
                Style = this.DataGrid.DragOverColumnStyle,
                Width = this.SourceViewColumn.RenderWidth,
                Height = this.DataGrid.ColumnHeaderHeight
            };
            this.DrawMarker(this._draggingLayer, new Point(this._lastMousePosition.X - this._sourceInnerOffset.X, this.SourceViewColumn.Column.ActualCanUserGroup ? (this._lastMousePosition.Y - this._sourceInnerOffset.Y) : point.Y), marker);
            if (this._targetGroupingIndex >= 0)
            {
                Rect? indicatorPositionFromPoint = this.DataGrid.View.GroupingPresenter.GetIndicatorPositionFromPoint(this._lastMousePosition);
                if (indicatorPositionFromPoint.HasValue)
                {
                    ContentControl control = new ContentControl
                    {
                        Background = this.DataGrid.PressedBrush,
                        BorderThickness = this.DataGrid.BorderThickness,
                        Style = this.DataGrid.DropIndicatorStyle,
                        Width = indicatorPositionFromPoint.Value.Width,
                        Height = indicatorPositionFromPoint.Value.Height
                    };
                    this.DrawMarker(this._draggingLayer, new Point(indicatorPositionFromPoint.Value.X, indicatorPositionFromPoint.Value.Y), control);
                }
            }
            if (this.TargetViewColumn != null)
            {
                int displayIndex = this.TargetViewColumn.Column.DisplayIndex;
                int sourceIndex = this.SourceViewColumn.Column.DisplayIndex;
                if ((this.TargetColumnHeader != null) && !this.TargetColumnHeader.IsCollected)
                {
                    int dropIndex = this.CalculateTargetColumnIndex();
                    if (((dropIndex != sourceIndex) && (dropIndex != (sourceIndex + 1))) && !this.IsThereAFixedColumnBetween(sourceIndex, dropIndex))
                    {
                        double num4 = 4.0;
                        Point pos = this.TargetColumnHeader.TransformToVisual(this._canvas).Transform(new Point());
                        if (dropIndex > displayIndex)
                        {
                            pos.X += this.TargetColumnHeader.ActualWidth;
                        }
                        pos.X -= num4 / 2.0;
                        ContentControl control2 = new ContentControl
                        {
                            Background = this.DataGrid.PressedBrush,
                            BorderThickness = this.DataGrid.BorderThickness,
                            Style = this.DataGrid.DropIndicatorStyle,
                            Height = this.TargetColumnHeader.ActualHeight,
                            Width = num4
                        };
                        this.DrawMarker(this._draggingLayer, pos, control2);
                    }
                }
            }
        }

        private DataGridColumnHeaderPresenter GetColumnHeader(DragEventArgs e)
        {
            UIElement topMostParent = this.DataGrid.GetTopMostParent();
            foreach (UIElement element2 in this.DataGrid.HitTestProjectionWorkaround(e.GetPosition(topMostParent)))
            {
                if (element2 is DataGridColumnHeaderPresenter)
                {
                    DataGridColumnHeaderPresenter element = element2 as DataGridColumnHeaderPresenter;
                    if (element.ViewColumn != null)
                    {
                        if (element.Column.DisplayIndex >= this.DataGrid.FrozenColumnCount)
                        {
                            Point point = new Point();
                            if (element.TransformToVisual(this.ColumnsHeaderPanel).Transform(point).X < this.View.GetFrozenWidth(true))
                            {
                                continue;
                            }
                        }
                        return element;
                    }
                }
            }
            return null;
        }

        private DataGridColumnHeaderPresenter GetColumnHeader(ViewColumn viewColumn, bool groupHeader)
        {
            if (viewColumn == null)
            {
                return null;
            }
            if (groupHeader)
            {
                return viewColumn.GetGroupHeaderPresenter(false);
            }
            return viewColumn.GetHeaderPresenter(false);
        }

        private void InitializePopup()
        {
            if (this._popup.Child == null)
            {
                this._draggingLayer = new Canvas();
                this._fixedColumnsLayer = new Canvas();
                this._scrollableColumnsLayer = new Canvas();
                this._canvas = new Canvas();
                this._canvas.Children.Add(this._draggingLayer);
                this._canvas.Children.Add(this._fixedColumnsLayer);
                this._canvas.Children.Add(this._scrollableColumnsLayer);
                this._popup.Child = this._canvas;
            }
        }

        private bool IsThereAFixedColumnBetween(int sourceIndex, int dropIndex)
        {
            int num = ((sourceIndex - dropIndex) > 0) ? dropIndex : sourceIndex;
            int num2 = ((sourceIndex - dropIndex) > 0) ? sourceIndex : dropIndex;
            for (int i = num; i < num2; i++)
            {
                if ((i < this.DataGrid.Model.Columns.OrderedColumns.Length) && !this.DataGrid.Model.Columns.OrderedColumns[i].ActualCanUserMove)
                {
                    return true;
                }
            }
            return false;
        }

        private void OnDragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (this.dragging)
            {
                this.ClearLayers();
                this._scrollTimer.Stop();
                this.DataGrid.OnColumnHeaderDragCompleted(e);
                if (((this.DataGrid.Model.FocusAndEditingManager.CurrentEditingCell == null) && ((this.TargetViewColumn != null) || (this._targetGroupingIndex != -1))) && (this.SourceViewColumn != null))
                {
                    if (this.TargetViewColumn != null)
                    {
                        ViewColumn targetViewColumn = this.TargetViewColumn;
                        ViewColumn sourceViewColumn = this.SourceViewColumn;
                        if (sourceViewColumn.Column.Index != targetViewColumn.Column.Index)
                        {
                            int dropIndex = this.CalculateTargetColumnIndex();
                            if ((dropIndex != sourceViewColumn.Column.DisplayIndex) && !this.IsThereAFixedColumnBetween(sourceViewColumn.Column.DisplayIndex, dropIndex))
                            {
                                try
                                {
                                    this.View.Model.MoveColumn(sourceViewColumn.Column, (dropIndex > sourceViewColumn.Column.DisplayIndex) ? (dropIndex - 1) : dropIndex);
                                    if (this._selectedColumn != null)
                                    {
                                        DataGridCell cell = this.DataGrid[this._selectedRow, this._selectedColumn];
                                        if (this._selectedCellIsEditing)
                                        {
                                            this.DataGrid.BeginEdit(cell);
                                        }
                                        else
                                        {
                                            this.DataGrid.Model.SetCurrentCell(cell);
                                        }
                                    }
                                }
                                catch (DataGridFinalizeEditingException)
                                {
                                }
                            }
                        }
                    }
                    if (this._targetGroupingIndex >= 0)
                    {
                        try
                        {
                            this.View.Model.InsertGroup(this.SourceViewColumn.Column, !this.SourceIsInGroupingPanel ? this._targetGroupingIndex : (this._targetGroupingIndex + ((this._targetGroupingIndex > this.SourceViewColumn.Column.GroupState.Index) ? -1 : 0)));
                        }
                        catch (DataGridGroupException)
                        {
                        }
                    }
                    this.SourceViewColumn = null;
                }
            }
        }

        private void OnDragDelta(object sender, DragDeltaEventArgs e)
        {
            if (this.dragging)
            {
                this.ClearLayers();
                this._lastMousePosition = e.GetPosition(this._canvas);
                if (this.SourceViewColumn != null)
                {
                    this.DrawSourceMarkers();
                    this.TargetColumnHeader = null;
                    if (!this.SourceIsInGroupingPanel)
                    {
                        this.TargetColumnHeader = this.GetColumnHeader(e);
                        if ((this.TargetColumnHeader != null) && !this.SourceViewColumn.Column.ActualCanUserMove)
                        {
                            this.TargetColumnHeader = null;
                        }
                    }
                    this._targetGroupingIndex = -1;
                    if ((!string.IsNullOrEmpty(this.SourceViewColumn.Column.ActualSortMemberPath) && this.SourceViewColumn.Column.ActualCanUserGroup) && (this.DataGrid.View.GroupingPresenter != null))
                    {
                        int indicatorIndexFromPoint = this.DataGrid.View.GroupingPresenter.GetIndicatorIndexFromPoint(this._lastMousePosition);
                        if (indicatorIndexFromPoint >= 0)
                        {
                            int index = this.SourceViewColumn.Column.GroupState.Index;
                            if ((!this.SourceIsInGroupingPanel && !this.View.Model.GroupManager.GroupedColumns.Contains<DataGridColumn>(this.SourceViewColumn.Column)) || ((this.SourceIsInGroupingPanel && (indicatorIndexFromPoint != index)) && (indicatorIndexFromPoint != (index + 1))))
                            {
                                this._targetGroupingIndex = indicatorIndexFromPoint;
                            }
                        }
                    }
                    this.DrawTargetMarkers();
                    if (!this.SourceIsInGroupingPanel)
                    {
                        Point point = this.ColumnsHeaderPanel.TransformToVisual(this._canvas).Transform(new Point());
                        Point position = e.GetPosition(this._canvas);
                        this._scrollOffset = (position.X <= (point.X + this.View.GetFrozenWidth(true))) ? ((double)(-20)) : ((position.X >= (point.X + this.View.RowsPanel.RenderSize.Width)) ? ((double)20) : ((double)0));
                        if (this._scrollOffset != 0.0)
                        {
                            if (!this._scrollTimer.IsEnabled)
                            {
                                this._scrollTimer.Start();
                            }
                        }
                        else
                        {
                            this._scrollTimer.Stop();
                        }
                    }
                    this.ClipColumnLayers();
                    this.DataGrid.OnColumnHeaderDragDelta(e);
                }
            }
        }

        private void OnDragStarted(object sender, DragStartedEventArgs e)
        {
            this.InitializePopup();
            if (!this._popup.IsOpen)
            {
                this._popup.IsOpen = true;
            }
            this.ClearLayers();
            DataGridColumnHeaderPresenter relativeTo = null;
            this.SourceViewColumn = null;
            if (sender == this.ColumnsHeaderPanel)
            {
                Point point = e.GetPosition(this.ColumnsHeaderPanel);
                RelativePosition relativePositionHorizontally = this.View.ScrollManager.GetRelativePositionHorizontally(point.X, null);
                if ((relativePositionHorizontally.Index >= 0) && (relativePositionHorizontally.Index < this.View.Model.Columns.OrderedColumns.Length))
                {
                    relativeTo = this.View.Model.Columns.OrderedColumns[relativePositionHorizontally.Index].HeaderPresenter;
                    this.SourceViewColumn = relativeTo.ViewColumn;
                }
                this.SourceIsInGroupingPanel = false;
            }
            else
            {
                Point position = e.GetPosition(null);
                relativeTo = (from elem in this.GroupingPresenter.HitTest(position)
                              where elem is DataGridColumnHeaderPresenter
                              select elem).FirstOrDefault<UIElement>() as DataGridColumnHeaderPresenter;
                if (relativeTo != null)
                {
                    this.SourceViewColumn = relativeTo.ViewColumn;
                    this.SourceIsInGroupingPanel = true;
                }
            }
            if (relativeTo != null)
            {
                this.dragging = true;
                if (((this.SourceViewColumn == null) || !relativeTo.IsSingleton) || ((this.SourceIsInGroupingPanel || !this.SourceViewColumn.Column.ActualCanUserMove) && !this.SourceViewColumn.Column.ActualCanUserGroup))
                {
                    this.dragging = false;
                }
                else
                {
                    this._sourceInnerOffset = e.GetPosition(relativeTo);
                    this._selectedColumn = null;
                    this._selectedCellIsEditing = false;
                    DataGridCell currentCell = this.DataGrid.Model.FocusAndEditingManager.CurrentCell;
                    if (currentCell != null)
                    {
                        this._selectedRow = currentCell.Row;
                        this._selectedColumn = currentCell.Column;
                        if (this.DataGrid.Model.FocusAndEditingManager.CurrentEditingCell != null)
                        {
                            this._selectedCellIsEditing = true;
                            if (!this.DataGrid.EndEdit())
                            {
                                return;
                            }
                        }
                    }
                    this.DrawSourceMarkers();
                    this.DataGrid.OnColumnHeaderDragStarted(e);
                }
            }
        }

        private void ScrollTick(object sender, EventArgs e)
        {
            double horizontalOffset = Math.Max(0.0, Math.Min((double)(this.View.ScrollManager.HorizontalOffset + this._scrollOffset), (double)(this.View.ScrollManager.ExtentWidth - this.View.ScrollManager.ScrollingWidth)));
            if (horizontalOffset == this.View.ScrollManager.HorizontalOffset)
            {
                this._scrollTimer.Stop();
            }
            else
            {
                this.View.ScrollManager.ScrollHorizontally(horizontalOffset);
                this.DataGrid.UpdateLayout();
                this.ClearLayers();
                this.DrawSourceMarkers();
                this.DrawTargetMarkers();
            }
        }

        // Properties
        public DataGridColumnsHeaderPanel ColumnsHeaderPanel
        {
            get
            {
                return this.View.ColumnsHeaderPanel;
            }
        }

        internal DataGrid DataGrid
        {
            get
            {
                return this.View.DataGrid;
            }
        }

        public DataGridGroupingPresenter GroupingPresenter
        {
            get
            {
                return this.View.GroupingPresenter;
            }
        }

        private ViewColumn TargetViewColumn
        {
            get
            {
                if (this.TargetColumnHeader == null)
                {
                    return null;
                }
                return this.TargetColumnHeader.ViewColumn;
            }
        }

        internal DataGridView View { get; private set; }
    }
}
